package com.sylli.oeuf.server.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import org.slf4j.Logger;

public class StringUtil {
	
	// debugger
	@SuppressWarnings("unchecked")
	public static void printArray(Logger log, Map map) {
    	int i = 0;
    	if (map.keySet().isEmpty()) {
    		log.debug("\t<Map is empty>");
    	} else {
    		for (Object key : map.keySet()) {
        		Object value = map.get(key);
        		log.debug("\t[" + (++i) + "] <"+ key + ">{" + value.getClass().getName() + "}" + value.toString());
        	}
    	}
	}
	
	public static void printArray1D(Logger log, Collection<Object> coll) {
    	int i=0;
    	if (coll.isEmpty()) {
    		log.debug("\t<Collection is empty>");
    	} else {
	    	for (Object para : coll) {
	    		log.debug("\t[" + (++i) + "] {" + para.getClass().getName() + "}=" + para.toString());
	    	}
    	}
	}

	public static void printArray(Logger log, Object[] params) {
    	int i=0;
    	if (params.length == 0) {
    		log.debug("\t<Array is empty>");
    	} else {
	    	for (Object para : params) {
	    		log.debug("\t[" + (++i) + "] {" + para.getClass().getName() + "}=" + para.toString());
	    	}
    	}
	}
	
	public static String encrypt(SecretKey key, byte[] message) {
		DesEncrypter encrypter = new DesEncrypter(key);
		return encrypter.encryptBytes(message);
	}
	
	public static String encrypt(String key, byte[] message) throws InvalidKeyException {
		DesEncrypter encrypter = new DesEncrypter(generateKey(key));
		return encrypter.encryptBytes(message);
	}
	
	public static byte[] descryptToBytes(SecretKey key, String encodedMsg) {
		DesEncrypter encrypter = new DesEncrypter(key);
		return encrypter.decryptBytes(encodedMsg);
	}
	
	public static byte[] descryptToBytes(String key, String encodedMsg) throws InvalidKeyException {
		DesEncrypter encrypter = new DesEncrypter(generateKey(key));
		return encrypter.decryptBytes(encodedMsg);
	}
	
	public static String encrypt(SecretKey key, String message) {
		DesEncrypter encrypter = new DesEncrypter(key);
		return encrypter.encryptString(message);
	}

	public static String encrypt(String key, String message) throws InvalidKeyException {
		DesEncrypter encrypter = new DesEncrypter(generateKey(key));
		return encrypter.encryptString(message);
	}
	
	public static String descryptToString(SecretKey key, String encodedMsg) {
		DesEncrypter encrypter = new DesEncrypter(key);
		return encrypter.decryptString(encodedMsg);
	}
	
	public static String descryptToString(String key, String encodedMsg) throws InvalidKeyException {
		DesEncrypter encrypter = new DesEncrypter(generateKey(key));
		return encrypter.decryptString(encodedMsg);
	}
	
	public static SecretKey generateKey(String pass_8_char_long) throws InvalidKeyException {
		return DesEncrypter.generateKeyFromPasswordString(pass_8_char_long);
	}
	
	public static boolean isPrintableChar(char c) {
		return Pattern.matches("a*b", "aaaaab");
	}
}

class DesEncrypter {
    Cipher ecipher;
    Cipher dcipher;

    DesEncrypter(SecretKey key) {
        try {
            ecipher = Cipher.getInstance("DES");
            dcipher = Cipher.getInstance("DES");
            ecipher.init(Cipher.ENCRYPT_MODE, key);
            dcipher.init(Cipher.DECRYPT_MODE, key);

        } catch (javax.crypto.NoSuchPaddingException e) {
        } catch (java.security.NoSuchAlgorithmException e) {
        } catch (java.security.InvalidKeyException e) {
        }
    }

    public static SecretKey generateKeyFromPasswordString(String pass) throws InvalidKeyException {
		SecretKey key = null;
		
		DESKeySpec ks = new DESKeySpec( pass.getBytes() );	// required 8 bytes at least
	    SecretKeyFactory factory;
		try {
			factory = SecretKeyFactory.getInstance( "DES" );
			key = factory.generateSecret( ks );
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return key;
    }
    
    public String encryptString(String str) {
        try {
            // Encode the string into bytes using utf-8
            byte[] utf8 = str.getBytes("UTF8");
            // re-adjust the bytes accordingly to the protocol
            byte[] arranged = utf8;
            
            // Encrypt
            byte[] enc = ecipher.doFinal(arranged);

            // Encode bytes to base64 to get a string
            return new sun.misc.BASE64Encoder().encode(enc);
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
        } catch (UnsupportedEncodingException e) {
        }
        return null;
    }
    
    public String encryptBytes(byte[] bytes) {
        try {
            // re-adjust the bytes accordingly to the protocol
            byte[] arranged = bytes;
            
            // Encrypt
            byte[] enc = ecipher.doFinal(arranged);

            // Encode bytes to base64 to get a string
            return new sun.misc.BASE64Encoder().encode(enc);
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
        }
        return null;
    }

    public String decryptString(String str) {
        try {
            // Decode base64 to get bytes
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

            // Decrypt
            byte[] unarranged = dcipher.doFinal(dec);
            // re-adjust the bytes accordingly to the protocol
            byte[] utf8 = unarranged;
            
            // Decode using utf-8
            return new String(utf8, "UTF8");
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
        } catch (UnsupportedEncodingException e) {
        } catch (java.io.IOException e) {
        }
        return null;
    }
    
    public byte[] decryptBytes(String str) {
        try {
            // Decode base64 to get bytes
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

            // Decrypt
            byte[] unarranged = dcipher.doFinal(dec);
            // re-adjust the bytes accordingly to the protocol
            byte[] arranged = unarranged;
            
            return arranged;
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
        } catch (UnsupportedEncodingException e) {
        } catch (java.io.IOException e) {
        }
        return null;
    }
}
